xen/arm: p2m: flush TLB by VMID when a new domain is creating
authorJulien Grall <julien.grall@linaro.org>
Thu, 14 Nov 2013 17:00:34 +0000 (17:00 +0000)
committerIan Campbell <ian.campbell@citrix.com>
Tue, 19 Nov 2013 14:37:41 +0000 (14:37 +0000)
Once the VMID is marked unused, a new domain can reuse the VMID for its
own. If the TLB is not flushed, entries can contain wrong translation.
When a new p2m is allocated, switch to the new VMID and flush TLB on
every physical CPUs.

Signed-off-by: Julien Grall <julien.grall@linaro.org>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
xen/arch/arm/p2m.c
xen/include/asm-arm/arm32/flushtlb.h
xen/include/asm-arm/arm64/flushtlb.h

index 2d09fef5d630ebdffbb74a41b1b910165d323e1d..82dda652c512a941464202e1716c600be9e2d6d1 100644 (file)
@@ -302,6 +302,15 @@ int p2m_alloc_table(struct domain *d)
     d->arch.vttbr = page_to_maddr(p2m->first_level)
         | ((uint64_t)p2m->vmid&0xff)<<48;
 
+    p2m_load_VTTBR(d);
+
+    /* Make sure that all TLBs corresponding to the new VMID are flushed
+     * before using it
+     */
+    flush_tlb();
+
+    p2m_load_VTTBR(current->domain);
+
     spin_unlock(&p2m->lock);
 
     return 0;
@@ -357,6 +366,7 @@ static void p2m_free_vmid(struct domain *d)
     spin_lock(&vmid_alloc_lock);
     if ( p2m->vmid != INVALID_VMID )
         clear_bit(p2m->vmid, vmid_mask);
+
     spin_unlock(&vmid_alloc_lock);
 }
 
index a258f58daac6bf6c94dd1522c7ed1f8d162b7c10..ab166f39a55da91f87a9531069aba419a8f24a48 100644 (file)
@@ -12,6 +12,17 @@ static inline void flush_tlb_local(void)
     isb();
 }
 
+/* Flush inner shareable TLBs, current VMID only */
+static inline void flush_tlb(void)
+{
+    dsb();
+
+    WRITE_CP32((uint32_t) 0, TLBIALLIS);
+
+    dsb();
+    isb();
+}
+
 /* Flush local TLBs, all VMIDs, non-hypervisor mode */
 static inline void flush_tlb_all_local(void)
 {
index d0535a06bb7c67a857691489786feb11dcc4ce5e..9ce79a86c37832da98316dd9f07a0883a64d6adc 100644 (file)
@@ -12,6 +12,17 @@ static inline void flush_tlb_local(void)
         : : : "memory");
 }
 
+/* Flush innershareable TLBs, current VMID only */
+static inline void flush_tlb(void)
+{
+    asm volatile(
+        "dsb sy;"
+        "tlbi vmalle1is;"
+        "dsb sy;"
+        "isb;"
+        : : : "memory");
+}
+
 /* Flush local TLBs, all VMIDs, non-hypervisor mode */
 static inline void flush_tlb_all_local(void)
 {